package me.samlss.lighter.view;

import me.samlss.lighter.animator.CustomAnimatorValue;
import me.samlss.lighter.interfaces.CustomDraggedListener;
import me.samlss.lighter.interfaces.FinishInflateListener;
import me.samlss.lighter.parameter.Direction;
import me.samlss.lighter.parameter.LighterParameter;
import me.samlss.lighter.parameter.MarginOffset;
import me.samlss.lighter.shape.LighterShape;
import me.samlss.lighter.util.LogUtil;
import me.samlss.lighter.util.ViewUtils;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

import java.util.List;

/**
 * Lighter核心自定义显示View
 *
 * @author: zhu_zhonglin
 * @time: 2021/4/25
 */
public class LighterView extends StackLayout implements Component.DrawTask {
    private final String TAG = getClass().getSimpleName();
    private List<LighterParameter> mLighterParameterList;
    private int mBgColor = -1;
    private int mInitWidth;
    private int mInitHeight;
    private boolean canDrag = true;//实收能拖拽滑动,默认能够拖动
    private ScrollHelper helper;

    public LighterView(Context context) {
        super(context);
        init();
    }

    public LighterView(Context context, boolean canDrag) {
        super(context);
        this.canDrag = canDrag;
        init();
    }

    public LighterView(Context context, AttrSet attrs) {
        super(context, attrs);
        init();
    }

    public LighterView(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        init();
    }

    /**
     * 设置Helper对象实例
     * @param helper helper
     */
    public void setHelper(ScrollHelper helper) {
        this.helper = helper;
    }

    private void init() {
        addDrawTask(this::onDraw);
        setTouchFocusable(true);
        if (!canDrag) {
            setDraggedListener(DragEvent.DRAG_BEGIN, new CustomDraggedListener() {
                @Override
                public boolean onDragPreAccept(Component component, int dragDirection) {
                    return !canDrag;
                }
            });
        }
    }

    /*@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        //need the exactly width & height
        measureChildren(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
        setMeasuredDimension(width, height);
    }*/

    /**
     * 释放参数
     */
    @Override
    public void release() {
        super.release();
        mLighterParameterList = null;
    }

    /**
     * reLayout 重新layout
     */
    public void reLayout() {
        for (int i = 0; i < getChildCount(); i++) {
            ViewUtils.calculateHighlightedViewRect(LighterView.this, mLighterParameterList.get(i));
            getComponentAt(i).setLayoutConfig(calculateLayoutParams(mInitWidth, mInitHeight, mLighterParameterList.get(i), getComponentAt(i)));
        }
    }

    /**
     * 替换背景色
     *
     * @param element
     */
    @Override
    public void setBackground(Element element) {
        super.setBackground(element);
        if (element instanceof ShapeElement) {
//            ShapeElement shapeElement = (ShapeElement) element;
//            RgbColor[] rgbColors = shapeElement.getRgbColors();
//            int alpha = shapeElement.getAlpha();
//            RgbColor rgbColor = rgbColors[0];
//            mBgColor = rgbColor.asArgbInt();
            LogUtil.loge(TAG, "mBgColor:" + mBgColor);
        }
    }

    /**
     * Add highlighted view, at the same time, multiple views can be highlighted
     *
     * @param lighterParameters The parameter of highlighted views.
     */
    public void addHighlight(List<LighterParameter> lighterParameters) {
        for (int i = 0; i < getChildCount(); i++) {
//            getComponentAt(i).clearAnimation();
            if (helper != null)
                helper.abortAnimation();
        }

        removeAllComponents();
        if (lighterParameters == null || lighterParameters.isEmpty()) {
            return;
        }

        mLighterParameterList = lighterParameters;

        for (LighterParameter lighterParameter : lighterParameters) {
            //check paramters
            addTipView(lighterParameter);
        }
    }

    /**
     * Add highlighted view
     *
     * @param lighterParameter The parameter of highlighted views.
     */
    public void addTipView(LighterParameter lighterParameter) {
        if (lighterParameter == null) {
            return;
        }

        //add tip view
        Component tipView = lighterParameter.getTipView();
        ComponentContainer.LayoutConfig layoutParams = calculateLayoutParams(mInitWidth, mInitHeight, lighterParameter, tipView);

        if (lighterParameter.getTipViewDisplayAnimation() != null) {
            AnimatorValue tipViewAnimation = lighterParameter.getTipViewDisplayAnimation();
            if (tipViewAnimation instanceof CustomAnimatorValue) {
                CustomAnimatorValue customAnimatorValue = (CustomAnimatorValue) tipViewAnimation;
                customAnimatorValue.animatorStart(tipView);
            }
        }
        LogUtil.loge(TAG, "addTipView");
        addComponent(tipView, layoutParams);
    }

    /**
     * calculateLayoutParams
     * @param width width
     * @param height height
     * @param lighterParameter lighterParameter
     * @param tipView tipView
     * @return LayoutConfig
     */
    private StackLayout.LayoutConfig calculateLayoutParams(int width, int height, LighterParameter lighterParameter, Component tipView) {
        RectFloat highlightedViewRect = lighterParameter.getHighlightedViewRect();

        MarginOffset marginOffset = lighterParameter.getTipViewRelativeMarginOffset();

        boolean autoVerticalFixed = lighterParameter.isAutoVerticalFixed();

        StackLayout.LayoutConfig layoutParams = (StackLayout.LayoutConfig) tipView.getLayoutConfig();
        if (layoutParams == null) {
            layoutParams = new StackLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        }

        if (highlightedViewRect == null || highlightedViewRect.isEmpty()) {
            return layoutParams;
        }

        boolean alignRight = false;
        switch (lighterParameter.getTipViewRelativeDirection()) {
            default:
            case Direction.LEFT:
                layoutParams.setMarginTop((int) highlightedViewRect.top + marginOffset.getTopOffset());
                layoutParams.setMarginRight((width - (int)highlightedViewRect.right + marginOffset.getRightOffset() + (int)highlightedViewRect.getWidth()));
                break;
            case Direction.RIGHT:
                layoutParams.setMarginTop((int) highlightedViewRect.top + marginOffset.getTopOffset());
                layoutParams.setMarginLeft((int)highlightedViewRect.right + marginOffset.getLeftOffset());
                break;

            case Direction.TOP:
                if ((double)highlightedViewRect.left > (double) width / 2) { //on the right
                    alignRight = true;
                    layoutParams.setMarginRight(width - (int)highlightedViewRect.right + marginOffset.getRightOffset());
                } else { //on the left
                    layoutParams.setMarginLeft((int) highlightedViewRect.left + marginOffset.getLeftOffset());
                }
                int topHeight = (int) highlightedViewRect.bottom - ((int)highlightedViewRect.getHeight() + marginOffset.getBottomOffset());
                LogUtil.loge(TAG, "highlightedViewRect: " + highlightedViewRect.getHeight() + " height: " + height + "=== topHeight: " + topHeight);

                if (autoVerticalFixed) {
                    if (topHeight < highlightedViewRect.getHeight()) {
                        layoutParams.setMarginTop((int)highlightedViewRect.bottom + marginOffset.getBottomOffset());
                    } else {
                        layoutParams.setMarginBottom(height - topHeight);
                    }
                } else {
                    layoutParams.setMarginBottom(height - topHeight);
                }
                break;

            case Direction.BOTTOM:
                if ((int)highlightedViewRect.left > width / 2) { //on the right
                    alignRight = true;
                    layoutParams.setMarginRight(width - (int)highlightedViewRect.right + marginOffset.getRightOffset());
                } else { //on the left
                    layoutParams.setMarginLeft((int)highlightedViewRect.left + marginOffset.getLeftOffset());
                }
                layoutParams.setMarginTop((int)highlightedViewRect.bottom + marginOffset.getTopOffset());
                break;
        }


        if (layoutParams.getMarginRight() != 0 || alignRight) {
            layoutParams.alignment = LayoutAlignment.RIGHT;
        } else {
            layoutParams.alignment = LayoutAlignment.LEFT;
        }

        if (layoutParams.getMarginBottom() != 0) {
            layoutParams.alignment |= LayoutAlignment.BOTTOM;
        } else {
            layoutParams.alignment |= LayoutAlignment.TOP;
        }

        return layoutParams;
    }

    /**
     * Check if the shape is empty.
     *
     * @param lighterShape
     * @return shape 是否为空
     */
    private boolean isShapeEmpty(LighterShape lighterShape) {
        return lighterShape == null
                || lighterShape.getViewRect() == null
                || lighterShape.getViewRect().isEmpty();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        LogUtil.loge(TAG, "=== onDraw ===========");
        if (mBgColor == -1) {
            mBgColor = ViewUtils.DEFAULT_HIGHLIGHT_VIEW_BG_COLOR;
        }

        LogUtil.loge(TAG, "===mBgColor " + mBgColor);

        //firstly, clip the rects of all the highlighted views.
        if (mLighterParameterList != null && !mLighterParameterList.isEmpty()) {
            for (LighterParameter lighterParameter : mLighterParameterList) {

                if (lighterParameter.getHighlightedView() == null
                        || lighterParameter.getLighterShape() == null
                        || lighterParameter.getLighterShape().getViewRect() == null
                        || lighterParameter.getLighterShape().getViewRect().isEmpty()) {

                    continue;
                }
                canvas.clipPath(lighterParameter.getLighterShape().getShapePath(), Canvas.ClipOp.DIFFERENCE);
            }
        }

//        Paint paint = new Paint();
//        Color color = new Color(Color.getIntColor("#B3000000"));
//        paint.setColor(color);
////        paint.setColorFilter(new ColorFilter(mBgColor, BlendMode.SRC_OUT));
//        RectFloat rectFloat = new RectFloat(0, 0, getWidth(), getHeight());
//        canvas.drawRect(rectFloat, paint);

        canvas.drawColor(mBgColor, Canvas.PorterDuffMode.SRC_OVER);


        //finally, draw the rects of all the highlighted views.
        if (mLighterParameterList != null && !mLighterParameterList.isEmpty()) {
            for (LighterParameter lighterParameter : mLighterParameterList) {
                if (isShapeEmpty(lighterParameter.getLighterShape())) {
                    continue;
                }
                LogUtil.loge(TAG, " ===getLighterShape " + (lighterParameter.getLighterShape() == null));
                lighterParameter.getLighterShape().onDraw(canvas);
            }
        }
        LogUtil.loge(TAG, "===finishDraw");


        if (listener != null) {
            listener.finishInflate();
        }
    }

    private FinishInflateListener listener;

    /**
     *  设置listener
     *
     * @param listener
     */
    public void setListener(FinishInflateListener listener) {
        this.listener = listener;
    }
    /**
     *  设置初始高度
     *
     * @param initHeight
     */
    public void setInitHeight(int initHeight) {
        this.mInitHeight = initHeight;
    }
    /**
     *  设置初始宽度
     *
     * @param initWidth
     */
    public void setInitWidth(int initWidth) {
        this.mInitWidth = initWidth;
    }

}
